package ru.niir.goodfil.ui;

import org.apache.commons.lang.StringUtils;
import ru.niir.goodfil.db.*;
import ru.niir.goodfil.db.dic.DeliveryType;
import ru.niir.goodfil.db.dic.OrderState;
import ru.niir.goodfil.db.dic.StorageDeliveryState;
import ru.niir.goodfil.exceptions.RemoveFailureException;
import ru.niir.goodfil.exceptions.ValidationException;
import ru.niir.goodfil.ui.utils.RestsExportManager;
import ru.niir.goodfil.ui.utils.excel.StorageDeliveryUnloading;
import ru.niir.goodfil.ui.utils.totalcount.TotalCount;
import ru.niir.goodfil.utils.ExportStringFormatter;
import ru.niir.goodfil.utils.Pair;

import javax.faces.model.ListDataModel;
import javax.faces.model.SelectItem;
import javax.mail.MessagingException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * Лист развоза. Вопросы:
 * 1. Как изменять элемент при изменении даты отгрузки???
 * 2. Если заказ в указанную дату не развезен, он удаляется из листа развоза на текущую дату и переносится на следующую
 * или должен отображаться и там и там????
 */
public class StorageDeliveryListBean extends PageBean {

    public static final String BEAN_NAME = "DeliveryStatus";

    public static final String LIST_PAGE = "status";
    /**
     * Выбранная дата
     */
    private Date selectedDate;

    /**
     * Элементы листа развоза
     */
    private List<StorageDeliveryStatus> itemList;

    /**
     * Дата самого раннего не сохраненного листа развоза
     */
    private Date errorDate;

    /**
     * Водители
     */
    private List<SelectItem> drivers;

    /**
     * Обертка для элементов листа развоза
     */
    private ListDataModel model;

    /**
     * Элемент для setPropertyActionListener
     */
    private long statusId;

    private StorageDeliveryStatus status;

    private List<TotalCount.DeliveryCount> deliveryCounts;

    public StorageDeliveryListBean() {
        init();
    }

    public void init() {
        Calendar calendar = Calendar.getInstance();
        setSelectedDate(calendar.getTime());
        itemList = getItems();
        model = new ListDataModel(itemList);
        List<StorageDeliveryStatus> deliveryStatusList = getOutStandingStorageDeliveryStatuses();
        errorDate = deliveryStatusList.size() != 0 ? deliveryStatusList.get(0).getDate() : null;
        drivers = new ArrayList<SelectItem>();
        drivers.add(new SelectItem(-1, "Не выбрано"));
        for (Driver driver : gf().getDrivers()) {
            drivers.add(new SelectItem(driver.getId(), driver.getFio()));
        }
        TotalCount totalCount = new TotalCount();
        setDeliveryCounts(totalCount.getTotalDeliveryInfo(itemList));
    }

    public List<StorageDeliveryStatus> getItems() {
        List<StorageDeliveryStatus> result = new ArrayList<StorageDeliveryStatus>();
        List<StorageDeliveryStatus> list = gf().getItemsForStorageDelivery(selectedDate);
        for (StorageDeliveryStatus storageDeliveryStatus : list) {
            // Получаем соответствующий заказ, получаем информацию о заказе
            Order order = gf().getOrderById(storageDeliveryStatus.getIdOrder());
            order.setClient(gf().getClientById(order.getClientId()));
            order.setManager(gf().getUserById(order.getManagerId()));
            gf().addOrderInfo(order);
            //Устанавливаем объем и вес
            List<OrderItem> orderItems = gf().getOrderItemsByOrderId(order.getId());
            double volume = 0;
            double weight = 0;
            for (OrderItem item : orderItems) {
                volume += gf().getGoodById(item.getGoodId()).getVolume() * item.getCount();
                weight += gf().getGoodById(item.getGoodId()).getWeight() * item.getCount();
            }
            order.setOrderVolume(volume);
            order.setOrderWeight(weight);
            // Устанавливаем информацию для водителей
            order.setDriverInfo(new ExportStringFormatter(order, orderItems).formatExportStringforDeliveryList());
            order.setDeliveryComment(new ExportStringFormatter(order, orderItems).formatExportStringforContactAndComment());
            order.setAdress(new ExportStringFormatter(order, orderItems).formatShortExportString());
            // Привязываем заказ к объекту листа развоза
            storageDeliveryStatus.setOrder(order);
            // Если статус доставки "загружено" или "доставлено" и тип доставки - ТК, то привязываем установленного водителя
            if (order.getDeliveryTypeId() == DeliveryType.COMPANY) {
                if (storageDeliveryStatus.isDeliveryStateIsCharge() || storageDeliveryStatus.isDeliveryStateIsDelivery()) {
                    storageDeliveryStatus.setDriver(gf().getDriverById(storageDeliveryStatus.getDriverId()));
                }
            }
            result.add(storageDeliveryStatus);
        }

        return result;
    }

    public void reloadData() {
        if (hasFacesErrors()) return;
        itemList = getItems();
        setModel(new ListDataModel(itemList));
        setSelectedDate(selectedDate);
        TotalCount totalCount = new TotalCount();
        setDeliveryCounts(totalCount.getTotalDeliveryInfo(itemList));
    }

    public void currentStorageDeliveryListToExcel() {
        if(itemList.size() == 0){
            facesError("Нет элементов для выгрузки");
            return;
        }
        StorageDeliveryUnloading.storageDeliveryListToExcel(itemList);
        reloadData();
    }

    public void shortStorageDeliveryListToExcel(){
        if(itemList.size() == 0){
            facesError("Нет элементов для выгрузки");
            return;
        }
        StorageDeliveryUnloading.shortStorageDeliveryListToExcel(itemList);
    }

    /*
    ==============================================================================================================================================
    Гетеры, сетеры, флаги для отображений
     */
    public Date getSelectedDate() {
        if (selectedDate == null) {
            return null;
        } else {
            return new java.util.Date(selectedDate.getTime());
        }
    }

    public void setSelectedDate(Date selectedDate) {
        if (selectedDate != null) {
            this.selectedDate = new java.sql.Date(selectedDate.getTime());
        } else {
            this.selectedDate = null;
        }
    }

    public ListDataModel getModel() {
        return model;
    }

    public void setModel(ListDataModel model) {
        this.model = model;
    }

    public Date getErrorDate() {
        return errorDate;
    }

    public void setErrorDate(Date errorDate) {
        this.errorDate = errorDate;
    }

    /**
     * Элементы листа развоза на более раннюю дату, которые не были сохранены
     *
     * @return коллеция элементов листа развоза
     */
    public List<StorageDeliveryStatus> getOutStandingStorageDeliveryStatuses() {
        return gf().getOutstandingStorageDeliveryStatus(selectedDate);
    }

    /**
     * Можно ли редактировать заполняемые поля
     *
     * @return
     */
    public boolean isReadOnly() {
        // Если клиент или менеджер, то редактировать нельзя
        if (getSecurityBean().getIsRoleManager() || getSecurityBean().getIsRoleClient() || getSecurityBean().getIsRoleKassa())
            return false;
        //Если есть несохраненные элементы в более ранних листах развоза, редактировать нельзя
        if (getOutStandingStorageDeliveryStatuses().size() != 0) return false;
        return true;
    }

    /**
     * Нужно ли отображать сообщение об ошибке, что есть не сохраненный лист развоза на более раннюю дату
     *
     * @return
     */
    public boolean isRenderDateMessage() {
        return errorDate != null && errorDate.before(selectedDate) && !getSecurityBean().getIsRoleManager();
    }

    public List<SelectItem> getStorageDeliveryStateList() {
        List<SelectItem> list = new ArrayList<SelectItem>();
        list.add(new SelectItem(-1, "НЕ ВЫБР."));
        for (Pair pair : StorageDeliveryState.list()) {
            list.add(new SelectItem(pair.getId(), pair.getValue()));
        }
        return list;
    }

    public List<SelectItem> getDrivers() {
        return drivers;
    }

    public long getStatusId() {
        return statusId;
    }

    public void setStatusId(long statusId) {
        this.statusId = statusId;
    }

    public List<TotalCount.DeliveryCount> getDeliveryCounts() {
        return deliveryCounts;
    }

    public void setDeliveryCounts(List<TotalCount.DeliveryCount> deliveryCounts) {
        this.deliveryCounts = deliveryCounts;
    }

    public TotalCount.DeliveryCount getDelivery(){
        return getDeliveryCounts().get(0);
    }

    public TotalCount.DeliveryCount getNotDelivery(){
        return getDeliveryCounts().get(1);
    }

    public void removeStorageDeliveryStatus() {
        try {
            RestsExportManager.sendStorageDeliveryChangeMessageForStoreKeeper(gf(), gf().getStorageDeliveryStatusById(statusId).getIdOrder());
            gf().removeStorageDelviveryStatus(statusId);
        } catch (RemoveFailureException e) {
            e.printStackTrace();
        } catch (MessagingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public synchronized void updateStorageDeliveryStatus() {
        if (hasFacesErrors()) return;

        if(status.getIdDeliveryType() != DeliveryType.TRANSPORT_COMPANY_RETURN){
            if(StringUtils.isBlank(status.getDocumentNum1C())){
                StorageDeliveryStatus statusFromDb = gf().getStorageDeliveryStatusById(status.getId());
                if(!StringUtils.isBlank(statusFromDb.getDocumentNum1C())) status.setDocumentNum1C(statusFromDb.getDocumentNum1C());
                else if(!status.isDeliveryStateIsNotDelivery()){
                    facesError("Поле \"№ 1С\" обязательно для заполнения");
                    return;
                }
            }
        }


        if (status.getDeliveryState() == -1) {
            facesError("Необходимо выбрать статус заказа");
            return;
        }

        if (status.isDeliveryStateIsNotDelivery()) {
            if (status.getComment().equals("")) {
                facesError("Если заказ не доставлен, необходимо заполнить поле \"Комментарий\"");
                return;
            }
        }
        if ((status.getIdDeliveryType() == DeliveryType.COMPANY || status.getIdDeliveryType() == DeliveryType.TRANSPORT_COMPANY_RETURN) && !status.isDeliveryStateIsNotDelivery() && status.getDriverId() == -1) {
            facesError("Необходимо установить водителя");
            return;
        }
        if (status.isDeliveryStateIsCharge() || status.isDeliveryStateIsDelivery()) {
            status.getOrder().setFactDeliveryDate(new Date());
            try {
                gf().updateOrder(status.getOrder());
            } catch (ValidationException e) {
                e.printStackTrace();
            }
        }

        // Если доставлено, то изменить статус заказа на "Обработка завершена"
        if (status.isDeliveryStateIsDelivery() && !status.getOrder().getOrderStateIsComplete()) {
            gf().setOrderState_Unsafe(status.getIdOrder(), OrderState.COMPLETE);
        }

        if (!status.isDeliveryStateIsCharge()) {
            status.setSaved(true);
        }
        try {
            gf().updateStorageDeliveryStatus(status);
            facesInfo("Сохранено");
        } catch (ValidationException e) {
            e.printStackTrace();
        }
    }

    public void updateStorageDeliveryStatusByKassa(){
        if(getSecurityBean().getIsRoleKassa()){
            if(StringUtils.isBlank(status.getDocumentNum1C())){
                StorageDeliveryStatus statusFromDb = gf().getStorageDeliveryStatusById(status.getId());
                if(!StringUtils.isBlank(statusFromDb.getDocumentNum1C())){
                    status.setDocumentNum1C(statusFromDb.getDocumentNum1C());
                    status.setComment(statusFromDb.getComment());
                    status.setDriverId(statusFromDb.getDriverId());
                    status.setLoadingDate(statusFromDb.getLoadingDate());
                    status.setDeliveryState(statusFromDb.getDeliveryState());
                }
                else {
                    facesError("Поле \"№ 1С\" обязательно для заполнения");
                    return;
                }
            }
            try {
                gf().updateStorageDeliveryStatus(status);
            } catch (ValidationException e) {
                e.printStackTrace();
            }
        }
    }

    public StorageDeliveryStatus getStatus() {
        return status;
    }

    public void setStatus(StorageDeliveryStatus status) {
        this.status = status;
    }
}
